<?
/* @author Udo Schroeter <udo.schroeter@gmail.com>
 * @license dual license: LGPL / commercial use license
 */ 
?><style>
#combatlog_scroll {
  height: 350px;
  width: 320px;
  overflow: auto;
}
</style><?

function calcXPRewardForMob($mobId, &$xpCount, $characterLevel)
{
  $mobDS = DB_GetDataset('characters', $mobId);
  calcXPRewardForMobDS($mobDS, $xpCount);
}

function calcXPRewardForMobDS(&$mobDS, &$xpCount, $characterLevel)
{
  if ($mobDS['c_xpreward'] > 0)
    $xpCount += $mobDS['c_xpreward'];
  else
    $xpCount += $mobDS['c_level'];
  $xpCount -= floor($characterLevel / 3.0);
}

function calcXPRewardOther($xpBonus, $characterLevel, &$xpCount)
{
  $xpCount += $xpBonus;
  if ($xpCount < 0) $xpCount = 0;
}

function DisplayAttackerList(&$mobObjects)
{
  foreach($mobObjects as $obj)
  {
    ?><li><?= $obj->charDS['c_name'] ?></li><?
  }
}

function registerHistoryEvent(&$actionDS, $type, $text, &$character)
{
  $historyDS = array(
    'h_character' => $character->charDS['c_key'],
    'h_type' => $type,
    'h_action' => $actionDS['a_key'],
    'h_text' => $text,
    'h_count' => '1',
    'h_first' => date('Y-m-d H:i:s'),
    'h_last' => date('Y-m-d H:i:s'),
    'h_zone' => $actionDS['a_zone'],
    );
  DB_UpdateDataset('history', $historyDS);
}

function registerQuest(&$actionDS, &$character)
{
  $intro = explode('-done-', $actionDS['a_intro']);
  registerHistoryEvent(
    $actionDS,
    'quest', 
    getDefault($intro[1], 'Quest completed: '.$actionDS['a_name']), $character);
}

function registerDefeat(&$actionDS, &$character)
{
  $historyDS = DB_GetDatasetMatch('history', array(
    'h_character' => $character->charDS['c_key'],
    'h_type' => 'defeat',
    ));
  $historyDS['h_count']++;
  $historyDS['h_last'] = date('Y-m-d H:i:s');
  $historyDS['h_zone'] = $actionDS['a_zone'];
  DB_UpdateDataset('history', $historyDS);
}

function registerDuel(&$victor, &$defeated, $text = 'duel')
{
  $ds = array();
  $ds['count'] = DB_GetDatasetMatch('history', array(
    'h_character' => $victor->charDS['c_key'],
    'h_type' => 'duelcountv',
    ));
  $ds[] = DB_GetDatasetMatch('history', array(
    'h_character' => $victor->charDS['c_key'],
    'h_mob' => $defeated->charDS['c_key'],
    'h_type' => 'duelv',
    ));
  $ds[] = DB_GetDatasetMatch('history', array(
    'h_character' => $defeated->charDS['c_key'],
    'h_type' => 'duelcountd',
    ));
  $ds[] = DB_GetDatasetMatch('history', array(
    'h_mob' => $victor->charDS['c_key'],
    'h_character' => $defeated->charDS['c_key'],
    'h_type' => 'dueld',
    ));
  foreach($ds as $k => $d)
  {
    $d['h_first'] = getDefault($d['h_first'], date('Y-m-d H:i:s'));
    $d['h_last'] = date('Y-m-d H:i:s');
    $d['h_count']++;  
    DB_UpdateDataset('history', $d);
    $ds[$k] = $d;
  }  
  #AdminNotify('duel: '.$victor->charDS['c_name'].' vs '.$defeated->charDS['c_name'].' '.$text);
  return($ds['count']['h_count']);
}

function executeFight(&$mobObjects, &$playerCharacter, &$act)
{
  ?><table width="100%" cellspacing="0" cellpadding="0"><tr><td valign="top"><div id="combatlog_scroll"><table><?
  global $groupDamage;
  $initiativeList = makeInitiativeList($mobObjects);
  $signal = 'fight';
  $actr = 0;
  $xp = 0;
  $ap = 0;
  $playerDied = false;
  $deadPool = array();
  while($signal == 'fight' && $actr < 200 && sizeof($mobObjects)>1)
  {
    $actr++;
    foreach($initiativeList as $descriptor => $ini) if (isset($mobObjects[$descriptor]))
    {
      $actor = &$mobObjects[$descriptor];
      // check if somebody died
      $groupDamage[$descriptor] = $actor->getCharacterStat('HP');
      if (!$actor->checkStatus())
      {
        if ($actor->charDS['c_key'] == $playerCharacter->charDS['c_key'])
        {
          $playerDied = true;
          print('<tr><td></td><td><b style="color: red; font-size: 110%">...and then you are too weak to fight and slink away in shame...</b></td></tr>');
        }
        else
        {
          if ($actor->stats['deathtext'] != '')
            $deathtext = str_replace('$actor', $actor->name, $actor->stats['deathtext']);
          else
            $deathtext = $actor->name.' dies a painful death!';
          
          print('<tr><td><img src="img/icons/combat-dead.png" width="24"/></td><td><b>
            '.$deathtext.'</b></td></tr>');
          if (sizeof($act)>0)
            $playerCharacter->addHistoryKill($actor, $act);
        }
        $deadPool[] = &$actor;
        unset($mobObjects[$descriptor]);
        unset($initiativeList[$descriptor]);
      }
      else
      {
        do {
          $attackResult = makeAttack($actor, $mobObjects);
          ?><!-- <? ob_start(); print_r($attackResult); print(htmlentities(ob_get_clean())); ?> --><?
          if ($attackResult['result']) 
          {
            ?><tr><td><?
            if ($attackResult['attack']['critical'] == true) print('<img src="img/icons/combat-critical.png" align="left" width="24"/></td><td>CRITICAL HIT! ');
            else if (isset($attackResult['attack']['spell']))
              print('<img src="img/icons/combat-magic.png" align="left" width="24"/></td><td> 
                <b>'.$actor->charDS['c_name'].'</b> casts <b style="color: #ff00ff">'.$attackResult['attack']['spell'].'</b>!<br/>');
            else 
              print('<img src="img/icons/combat-hit.png" align="left" width="24"/></td><td> ');
            if ($actor->isDoingMultiple) print('MULTIPLE HIT!<br/>');
            print('<div class="'.$actor->stats['enemy'].'_enemy">'.$attackResult['msg'].'</div></td></tr>');
          }
          else
          {
            $signal = getDefault($attackResult['signal'], $signal);
          }
        } while ($actor->canDoMultiple());
      }
    }
  }
  ?></table></div></td><td valign="top">&nbsp;</td><td width="*" valign="top"><?
  
  $actionProperties = TextToStringList($act['a_stats']);
          
  if ($playerDied == true)
  {
    registerDefeat($act, $playerCharacter);
    print(getDefault($act['afterdefeat'], $act['afteraction']));
  }
  else
  {
    if ($act['a_type'] == 'Q')
    {
      registerQuest($act, $playerCharacter);
      if (isset($act['properties']['qzone']))
        $playerCharacter->charDS['c_location'] = $act['properties']['qzone'];
    }  
    $loot = array();
    foreach($deadPool as $mobObj)
    {
      $loot = array_merge($loot, dropItems($mobObj->stats));
      calcXPRewardForMobDS($mobObj->charDS, $xp, $playerCharacter->level);
      //$xp += $mobObj->charDS['c_level'];
    }
    calcXPRewardOther($act['a_xp'], $playerCharacter->level, $xp);
    $loot = array_merge($loot, dropItems($actionProperties));
    
    ?><div class="drop_list" style="padding: 4px; padding-left: 24px; background: #fff; width: 100%;"><b style="color: black">You acquired:</b><?
    if (sizeof($loot)>0)
    {
      foreach($loot as $lootItem)
      {
        $itemDS = DB_GetDataset('items', $lootItem['i_key']);
        if (sizeof($itemDS) == 0) $itemDS = DB_GetDataset('items', $lootItem['i_key'], 'i_shorthand');
        print('<li>'.$lootItem['#'].'x '.$itemDS['i_name']);
        $playerCharacter->addInventory($itemDS, $lootItem['#']);
        if ($itemDS['i_type'] == 'wearable')
          print(', <a class="linkbutton" href="'.actionUrl('equipment', 'character', 'on='.$itemDS['i_key']).'">use/equip</a> now');
        print('</li>');
      }
    }
    ?>
    <li>+<?= $xp ?> Experience Point<? if ($xp != 1) print('s'); ?></li>
    </div><br/><?
    print($act['afteraction']);
  } // end player loot and rewards
  
  // apply experience points earned
  $playerCharacter->stats['XP'] += $xp;
  // do automated housekeeping
  $playerCharacter->encounterAftermath($act);
  // save changes
  $playerCharacter->saveCharacter();
  ?></td></tr></table><?
}

function makeParticipantsFromAction(&$mobObjects, &$action, &$character)
{
  // make the character participate
  $descriptor = 'char.'.$character->charDS['c_key'];
  $mobObjects[$descriptor] = &$character;
  $mobObjects[$descriptor]->stats['enemy'] = 'mob';
  
  foreach($action['mobs'] as $mobDS)
  {
    $mobcount++;
    $mobMaxNameCount['m'.$mobDS['c_name']]++;
    $descriptor = 'mob.'.$mobDS['c_key'].'.'.$mobcount;
    $mobObjects[$descriptor] = new CharacterModel('', $descriptor, $mobDS['c_key']);
    CharacterModel::applyRaceToStats($mobObjects[$descriptor]->stats, $mobDS['c_race']);
    applyMobLevelToStats($mobObjects[$descriptor], $mobDS['c_level']);
    $mobObjects[$descriptor]->recalculateStats('mob');
    $mobObjects[$descriptor]->stats['enemy'] = 'char';
    ?><!--<?
    print_r($mobObjects[$descriptor]->stats);
    ?>--><?
  } 
  foreach($mobObjects as $descriptor => $obj)
  {
    $mobNameCount['m'.$obj->charDS['c_name']]++;
    if ($mobMaxNameCount['m'.$obj->charDS['c_name']] > 1)
    {
      $mobObjects[$descriptor]->charDS['c_name'] .= ' '.$mobNameCount['m'.$obj->charDS['c_name']];
      $mobObjects[$descriptor]->name = $mobObjects[$descriptor]->charDS['c_name'];
    }
  }       
  ?><!--<?
  print_r($mobMaxNameCount);
  ?>--><?
}

function applyMobLevelToStats(&$mob, $level = 1)
{
  if ($level > 1)
  {
    foreach($mob->attributes as $attribute)
    {
      if ($mob->stats[$attribute] != 0 && $attribute != 'ARMOR')
        $mob->stats[$attribute] = round($mob->stats[$attribute]+(($level-1)*2));
    }
  }
}

function makeInitiativeList(&$mobObjects)
{
  $result = array();
  foreach($mobObjects as $descriptor => $charObject)
  {
    $result[$descriptor] = $charObject->getCharacterStat('INT');
  }
  asort($result);
  return(array_reverse($result));
}

function getATarget(&$everyone, $type)
{
  $result = array();
  foreach ($everyone as $descriptor => $mobObject)
  {
    $thisType = CutSegment('.', $descriptor);
    if ($thisType == $type) $result[] = $type.'.'.$descriptor;
  }
  if (sizeof($result)>0)
    return($result[rand(0, sizeof($result)-1)]);
  return(null);
}

// make a nice text describing the attack
function getAttackVerb($dmgtype)
{
  $verbList = explode(',', AGController::l10n('dmgtype.'.$dmgtype, 'cq', 'en'));
  $verb = explode(':', $verbList[rand(0, sizeof($verbList)-1)]);
  if (substr($verb[1], 0, 1) != "'") $verb[1] = ' '.$verb[1];
  return($verb);
}

// when death occurs, drop some loot!
function dropItems(&$stats)
{
  global $ctrObj;
  $result = array();
  foreach($stats as $k => $v)
  {
    $type = CutSegment('.', $k);
    if ($type == 'drop')
    {
      $dropParams = explode(',', $v);
      // drop probability
      if (substr($dropParams[0], -1) == '%') $dropParams[0] = substr($dropParams[0], 0, -1);
      // min number of items
      $dropParams[1] = getDefault($dropParams[1], 1);
      // max number of items
      $dropParams[2] = getDefault($dropParams[2], $dropParams[1]);
      // determine if drop occurs
      if (rand(0,100) <= $dropParams[0]+0)
        $result[] = array('i_key' => $k, '#' => rand($dropParams[1], $dropParams[2]));
    }
    else if ($type == 'party')
    {
      $dropParams = explode(',', $v);
      // drop probability
      if (substr($dropParams[0], -1) == '%') $dropParams[0] = substr($dropParams[0], 0, -1);
      // min number of items
      $dropParams[1] = getDefault($dropParams[1], 1);
      // max number of items
      $dropParams[2] = getDefault($dropParams[2], $dropParams[1]);
      // determine if drop occurs
      if (rand(0,100) <= $dropParams[0]+0)
        $result[] = array('type' => 'party', 'c_key' => $k, '#' => rand($dropParams[1], $dropParams[2]));
    }
    else if ($type == 'buff')
    {
      $result[] = array('type' => 'buff', 'stat' => $k, 'value' => $v);
    }
  }
  if (1==2 && $ctrObj->character->charDS['c_key'] == 70)
  {
    ob_start();
    print_r($result);
    AdminNotify('drop', ob_get_clean());
  }
  return($result);
}

// execute an attack
function makeAttack(&$attacker, &$everyone)
{
  $targetDescriptor = getATarget($everyone, $attacker->stats['enemy']);
  $target = $everyone[$targetDescriptor];
  if (!isset($everyone[$targetDescriptor]))
    return(array(
      'result' => false,
      'signal' => 'endcombat',
      'enemy' => $attacker->stats['enemy'],
      'actor' => $attacker->charDS['c_name'],
      'targetdesc' => $targetDescriptor,
      'msg' => 'nobody left to attack!',
      ));
  
  $hitRecord = $attacker->makeHit();
  $hitSuccess = $target->takeHit($hitRecord);
  if (!$hitSuccess)
    return(array(
      'result' => false,
      'target' => $targetDescriptor,
      'attack' => $hitRecord,
      'msg' => $attacker->name.' fails at hitting '.$target->name.' ('.$hitRecord['hit'].' against a '.$hitRecord['dodge'].')',
      ));
  else
  {
    $damageRecord = $attacker->makeDamage($hitRecord);
    $damageTaken = $target->takeDamage($damageRecord);
    $damage = $damageRecord['damage'];
    if ($damageTaken == 0)
      return(array(
        'result' => false,
        'target' => $targetDescriptor,
        'attack' => $damageRecord,
        'msg' => $attacker->name.' hits '.$target->name.' too weakly to cause any damage ('.$damageRecord['damage'].
                 '-'.$damageRecord['reducedby'].')',
        ));
    else
    {
      $verb = getAttackVerb(getDefault($damageRecord['dmgtype'], 'hand'));
      $name = $target->name;
      return(array(
        'result' => true,
        'target' => $targetDescriptor,
        'attack' => $damageRecord,
        'msg' => '<b>'.$attacker->name.'</b> '.$verb[0].
          ' <b>'.$name.'</b>'.$verb[1].' for '.$damageTaken.' '.makePlural('damage point', $damageTaken).'.<!--('.$damageRecord['hp'].' HP)-->',
        ));
    }
  }
}


?>
<script>
document.combatlog_scrollstate = 0;
function combatScroll()
{
  var scrolldiv = document.getElementById('combatlog_scroll');
  if (scrolldiv)
  {
    scrolldiv.scrollTop += 3;
    if (document.combatlog_scrollstate != scrolldiv.scrollTop)
      setTimeout('combatScroll();', 30);
    document.combatlog_scrollstate = scrolldiv.scrollTop;
  }
  else
    setTimeout('combatScroll();', 500);
}
combatScroll();
</script>